package com.li.springbootproject.service.thread.impl;

import com.li.springbootproject.service.thread.ThreadTestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Description：
 * @Author：LiDong
 * @Create：2021/3/17
 * @Version：1.0.0
 */
@Service
public class ThreadTestServiceImpl implements ThreadTestService {

    private static final Logger logger = LoggerFactory.getLogger(ThreadTestServiceImpl.class);

    private static final HashSet hashSet = new HashSet();

    /**
     * 线程池，大小1
     */
    private static final ExecutorService executorService = Executors.newFixedThreadPool(1);

    @Autowired
    private Executor executor;

    private int num = 0;


    @Override
    public synchronized int sychnoizedTest() {
        for (int i = 0; i < 100; i++) {
            dealAddNum();
        }
        int sum = num;
        num = 0;
        return sum;
    }

    /**
     * 全局线程池配置测试
     */
    @Async("globalExecutor")
    @Override
    public void globalExecutorTest() {
        logger.info("test thread!");
    }

    private void dealAddNum() {
        try {
            num++;
            Thread.sleep(100);
        } catch (InterruptedException e) {
            logger.info(e.getMessage());
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 模拟堆栈溢出
     */
    @Override
    public void testOne() {
        while (true) {
            testOne();
        }
    }

    /**
     * 模拟堆溢出
     */
    @Override
    public void testTwo() {
        String name = "hello";
        for (int i = 0; i < 10000000; i++) {
            name += name;
        }
    }

    @Override
    public void testThree() {
        // 模拟 CPU 过高，这里注释掉了，测试时可以打开
        // cpu();
        // 模拟线程阻塞
        // thread();
        // 模拟线程死锁
        deadThread();
        // 不断的向 hashSet 集合增加数据
        // addHashSetThread();
    }

    /**
     * 不断的向 hashSet 集合添加数据
     */
    private void addHashSetThread() {
        // 初始化常量
        new Thread(() -> {
            int count = 0;
            while (true) {
                try {
                    hashSet.add("count" + count);
                    Thread.sleep(10000);
                    count++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void cpu() {
        cpuHigh();
        cpuNormal();
    }

    /**
     * 极度消耗CPU的线程
     */
    private void cpuHigh() {
        Thread thread = new Thread(() -> {
            while (true) {
                logger.info("cpu start 100");
            }
        });
        // 添加到线程
        executorService.submit(thread);
    }

    /**
     * 普通消耗CPU的线程
     */
    private void cpuNormal() {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                while (true) {
                    logger.info("cpu start");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    /**
     * 模拟线程阻塞,向已经满了的线程池提交线程
     */
    private void thread() {
        Thread thread = new Thread(() -> {
            while (true) {
                logger.debug("thread start");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        // 添加到线程
        executorService.submit(thread);
    }

    /**
     * 死锁
     */
    private static void deadThread() {
        /** 创建资源 */
        Object resourceA = new Object();
        Object resourceB = new Object();
        // 创建线程
        Thread threadA = new Thread(() -> {
            synchronized (resourceA) {
                logger.info(Thread.currentThread() + " get ResourceA");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                logger.info(Thread.currentThread() + "waiting get resourceB");
                synchronized (resourceB) {
                    logger.info(Thread.currentThread() + " get resourceB");
                }
            }
        });

        Thread threadB = new Thread(() -> {
            synchronized (resourceB) {
                logger.info(Thread.currentThread() + " get ResourceB");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                logger.info(Thread.currentThread() + "waiting get resourceA");
                synchronized (resourceA) {
                    logger.info(Thread.currentThread() + " get resourceA");
                }
            }
        });
        threadA.start();
        threadB.start();
    }
}
